package compilers.table;

import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

import org.antlr.runtime.Token;

import compilers.node.Identifier;
import compilers.output.ErrorOutput;
import compilers.types.Type;

public class Scope {

	Scope fParentScope = null;
	Map<String, Type> fVariables = new HashMap<String, Type>();
	
	public Scope(Scope parentScope) {
		fParentScope = parentScope;
	}
	
	public Scope getParent() {
		return fParentScope;
	}
	
	public void addVariable(String name, Type type, Token token) {
		int i = name.indexOf('[');
		if(i>0) {
			name = name.substring(0,i);
		}
		if (fVariables.get(name) != null) {
			new ErrorOutput(token, "Variable name already in use. (" + name + ")");
		}
		fVariables.put(name, type);
	}
	
	public Type resolveVariable(String name, Token token) {
		String orig = name;
		
		char c[] = name.toCharArray();
		for (int i = 0; i < c.length; i++) {
			if (c[i] == '[') {
				name = name.substring(0, i);
				break;
			}
		}
		
		Type vs = fVariables.get(name);
		
		Identifier tmp = new Identifier(orig, token, this);				
		if (!tmp.getIndices(token).isEmpty()) {
			// variables
			for (Map.Entry<String,Type> entry: fVariables.entrySet()) {
				Type t = (Type)entry.getValue();
				if (t.getfIdentifier().getfIdentifier().startsWith(name)) {
					Vector<Integer> ind1 = tmp.getIndices(token);
					Vector<Integer> ind2 = t.getfIdentifier().getIndices(token);
					if (ind1.size() == ind2.size()) {
						for (int i = 0; i < ind1.size(); i++) {
							if (ind2.get(i).intValue() <= ind1.get(i).intValue()) {
								new ErrorOutput(token, "Using array index larger than declared size (" + ind2.get(i).intValue() + "): " + ind1.get(i).intValue());
							}
						}
						vs = t;
					} else {
						new ErrorOutput(token, "Dimensions of array don't match.");
					}
				}
			}
		} else {
			// parameters
			for (Map.Entry<String,Type> entry: fVariables.entrySet()) {
				Type t = (Type)entry.getValue();
				if (t.getfIdentifier().getfIdentifier().startsWith(name)) {
					vs = t;
				}
			}
		}
		
		if (vs == null) {
			if (fParentScope != null) {
				return fParentScope.resolveVariable(name, token);
			} else {
				new ErrorOutput(token, "Variable doesn't exist. (" + name + ")");
			}
		}
		return vs.clone();
	}
	
}
